<template>
  <div class="main">
    <div :id="cid" class="item"></div>
    <el-card class="item sub">
      <div v-for="o in 4" :key="o">
        {{'图标说明 ' + o }}
      </div>
    </el-card>
  </div>
</template>

<script>
import * as d3 from 'd3';
import 'd3-scale'
import 'd3-shape'
import 'd3-array'
import 'd3-selection'
// import stateage from '../data/stateage.json'

export default {
  name: "DotPlot",
  props:['cid','height'],
  mounted() {
    this.axios.get('http://localhost:5000/api/stateage').then(res =>{
      this.DotPlot(res.data, {
        x: d => d.population,
        y: d => d.state,
        z: d => d.age,
        xFormat: "%",
        xLabel: "Population →",
      })
    }).catch()

  },
  methods:{
    DotPlot(data, {
      x = ([x]) => x, // given d in data, returns the (quantitative) value x
      y = ([, y]) => y, // given d in data, returns the (categorical) value y
      z = () => 1, // given d in data, returns the (categorical) value z
      r = 3.5, // (fixed) radius of dots, in pixels
      xFormat, // a format specifier for the x-axis
      marginTop = 30, // top margin, in pixels
      marginRight = 30, // right margin, in pixels
      marginBottom = 10, // bottom margin, in pixels
      marginLeft = 30, // left margin, in pixels
      width = 640, // outer width, in pixels
      height, // outer height, in pixels, defaults to heuristic
      xType = d3.scaleLinear, // type of x-scale
      xDomain, // [xmin, xmax]
      xRange = [marginLeft, width - marginRight], // [left, right]
      xLabel, // a label for the x-axis
      yDomain, // an array of (ordinal) y-values
      yRange, // [top, bottom]
      yPadding = 1, // separation for first and last dots from axis
      zDomain, // array of z-values
      colors, // color scheme
      stroke = "currentColor", // stroke of rule connecting dots
      strokeWidth, // stroke width of rule connecting dots
      strokeLinecap, // stroke line cap of rule connecting dots
      strokeOpacity, // stroke opacity of rule connecting dots
      duration: initialDuration = 250, // duration of transition, if any
      delay: initialDelay = (_, i) => i * 10, // delay of transition, if any
        } = {}){
      // Compute values.
      const X = d3.map(data, x);
      const Y = d3.map(data, y);
      const Z = d3.map(data, z);

      // Compute default domains, and unique them as needed.
      if (xDomain === undefined) xDomain = d3.extent(X);
      if (yDomain === undefined) yDomain = Y;
      if (zDomain === undefined) zDomain = Z;
      yDomain = new d3.InternSet(yDomain);
      zDomain = new d3.InternSet(zDomain);

      // Omit any data not present in the y- and z-domains.
      const I = d3.range(X.length).filter(i => yDomain.has(Y[i]) && zDomain.has(Z[i]));

      // Compute the default height.
      if (height === undefined) height = Math.ceil((yDomain.size + yPadding) * 16) + marginTop + marginBottom;
      if (yRange === undefined) yRange = [marginTop, height - marginBottom];

      // Chose a default color scheme based on cardinality.
      if (colors === undefined) colors = d3.schemeSpectral[zDomain.size];
      if (colors === undefined) colors = d3.quantize(d3.interpolateSpectral, zDomain.size);

      // Construct scales and axes.
      const xScale = xType(xDomain, xRange);
      const yScale = d3.scalePoint(yDomain, yRange).round(true).padding(yPadding);
      const color = d3.scaleOrdinal(zDomain, colors);
      const xAxis = d3.axisTop(xScale).ticks(width / 80, xFormat);

      const svg = d3.select(`#${this.cid}`).append('svg')
          .attr("width", width)
          .attr("height", height)
          .attr("viewBox", [0, 0, width, height])
          .attr("style", "max-width: 100%; height: auto; height: intrinsic;");

      svg.append("g")
          .attr("transform", `translate(0,${marginTop})`)
          .call(xAxis)
          .call(g => g.select(".domain").remove())
          .call(g => g.selectAll(".tick line").clone()
              .attr("y2", height - marginTop - marginBottom)
              .attr("stroke-opacity", 0.1))
          .call(g => g.append("text")
              .attr("x", width - marginRight)
              .attr("y", -22)
              .attr("fill", "currentColor")
              .attr("text-anchor", "end")
              .text(xLabel));

      const g = svg.append("g")
          .attr("text-anchor", "end")
          .attr("font-family", "sans-serif")
          .attr("font-size", 10)
          .selectAll()
          .data(d3.group(I, i => Y[i]))
          .join("g")
          .attr("transform", ([y]) => `translate(0,${yScale(y)})`);

      g.append("line")
          .attr("stroke", stroke)
          .attr("stroke-width", strokeWidth)
          .attr("stroke-linecap", strokeLinecap)
          .attr("stroke-opacity", strokeOpacity)
          .attr("x1", ([, I]) => xScale(d3.min(I, i => X[i])))
          .attr("x2", ([, I]) => xScale(d3.max(I, i => X[i])));

      g.selectAll("circle")
          .data(([, I]) => I)
          .join("circle")
          .attr("cx", i => xScale(X[i]))
          .attr("fill", i => color(Z[i]))
          .attr("r", r);

      g.append("text")
          .attr("dy", "0.35em")
          .attr("x", ([, I]) => xScale(d3.min(I, i => X[i])) - 6)
          .text(([y]) => y);

      return Object.assign(svg.node(), {
        color,
        update(yDomain, {
          duration = initialDuration, // duration of transition
          delay = initialDelay, // delay of transition
        } = {}) {
          yScale.domain(yDomain);
          const t = g.transition().duration(duration).delay(delay);
          t.attr("transform", ([y]) => `translate(0,${yScale(y)})`);
        }
      });
    }
  }
}
</script>

<style scoped>
.main{
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: flex-end
}
.item{
  flex-grow:1;
  flex-shrink:1;
}
.sub{
  max-width: 300px;
  min-width: 200px;
  flex-grow:1;
  flex-shrink:0;
}
</style>